package com.property.manage.service.parking;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.guardchina.framework.mybatis.model.CustomPage;
import com.guardchina.framework.util.exception.BusinessException;
import com.guardchina.framework.util.exception.SystemException;
import com.guardchina.framework.util.utils.DateUtil;
import com.guardchina.framework.util.utils.NumberToCn;
import com.property.manage.dao.parking.ParkingRentArrearsMapper;
import com.property.manage.enums.WalletType;
import com.property.manage.model.flowingWater.FlowingWaterEntity;
import com.property.manage.model.parking.*;
import com.property.manage.model.print.ArrearsPayBillVo;
import com.property.manage.model.resource.Building;
import com.property.manage.model.system.SysSet;
import com.property.manage.model.system.User;
import com.property.manage.model.village.Village;
import com.property.manage.service.flowingWater.FlowingWaterService;
import com.property.manage.service.flowingWater.WalletService;
import com.property.manage.service.resource.BuildingService;
import com.property.manage.service.system.SnowflakeIdWorker;
import com.property.manage.service.system.UserService;
import com.property.manage.service.village.VillageService;
import com.property.manage.util.ExportUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 描述
 *
 * @author lwb
 * @since 2020/9/15
 */
@Service
@Slf4j
public class ParkingRentArrearsService {

    private ParkingRentArrearsMapper parkingRentArrearsMapper;

    private WalletService walletService;

    private UserService userService;

    private ParkingRentPayRecordService parkingRentPayRecordService;

    @Value("${daily.running.parkingRentArrearsRecord}")
    private String tempFilePath;

    private SnowflakeIdWorker snowflakeIdWorker;

    private VillageService villageService;

    private BuildingService buildingService;

    private ParkingRentService parkingRentService;

    @Value("${timed.patee}")
    private String patee;

    @Value("${timed.receiveUnit}")
    private String receiveUnit;

    public void add(Integer rentId, BigDecimal money, String yearMonth, String remark, Integer buildingId) {

        ParkingRentArrearsEntity entity = new ParkingRentArrearsEntity();

        entity.setRentId(rentId);
        entity.setMoney(money);
        entity.setYearMonth(yearMonth);
        entity.setRemark(remark);
        entity.setCreateTime(LocalDateTime.now());
        entity.setState(ParkingRentArrearsEntity.STATE_NOT_PAY);
        entity.setBuildingId(buildingId);
        parkingRentArrearsMapper.insert(entity);
    }

    public CustomPage<ParkingRentArrearsVo> arrearsPage(Long pageNo, Long pageSize, Integer villageId, Integer building, Integer unit, String roomNumber, LocalDate startDate, LocalDate endDate) {
        Page<ParkingRentArrearsVo> page = new Page<>(pageNo, pageSize);

        LocalDateTime startTime = null;
        LocalDateTime endTime = null;

        if (startDate != null) {
            startTime = DateUtil.startTime(startDate);
        }

        if (endDate != null) {
            endTime = DateUtil.endTime(endDate);
        }

        IPage<ParkingRentArrearsVo> resultPage = parkingRentArrearsMapper.arrearsPage(page, villageId, building, unit, roomNumber, startTime, endTime);

        return new CustomPage<>(resultPage);
    }

    public List<ParkingRentArrearsDetailVo> arrearsDetailList(Integer buildingId) {
        return parkingRentArrearsMapper.arrearsDetailList(buildingId);
    }


    public void arrearsDetailExport(Integer villageId, Integer building, Integer unit, String roomNumber, LocalDate startDate, LocalDate endDate, HttpServletRequest request, HttpServletResponse response) {
        LocalDateTime startTime = null;
        LocalDateTime endTime = null;

        if (startDate != null) {
            startTime = DateUtil.startTime(startDate);
        }

        if (endDate != null) {
            endTime = DateUtil.endTime(endDate);
        }

        List<ParkingRentArrearsDetailVo> parkingRentArrearsDetailVos = parkingRentArrearsMapper.arrearsDetailExport(villageId, building, unit, roomNumber, startTime, endTime);

        try {
            XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(tempFilePath));
            // 根据页面index 获取sheet页
            XSSFSheet sheet = wb.getSheetAt(0);

            for (int i = 0; i < parkingRentArrearsDetailVos.size(); i++) {
                XSSFRow rw = sheet.createRow(i + 1);
                setCell(parkingRentArrearsDetailVos.get(i), rw);
            }

            ExportUtil.exportExcel(request, response, "车位租金欠费记录.xlsx", wb);
        } catch (IOException e) {
            throw new SystemException("导出失败", e);
        }

    }


    public ArrearsPayBillVo charge(Integer userId, Integer buildingId, String arrearsIds, BigDecimal totalMoney, BigDecimal chargeMoney, String payType, Boolean useStorage, Boolean storageReturn, Boolean print, String remark) {

        List<Integer> arrearsIdList = new Gson().fromJson(arrearsIds, new TypeToken<List<Integer>>() {
        }.getType());

        List<ParkingRentArrearsEntity> arrearsList = getList(arrearsIdList);

        BigDecimal dbTotalMoney = arrearsList.stream().map(ParkingRentArrearsEntity::getMoney).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);


        String remarks = arrearsList.stream().map(arrears -> {
            String yearMonth = arrears.getYearMonth();
//            yearMonth = yearMonth.substring(0, 4) + "-" + yearMonth.substring(4);
            yearMonth = yearMonth.substring(0, 4) + yearMonth.substring(4);

            return yearMonth;
        }).reduce((s1, s2) -> s1 + "、" + s2).orElse("");
        remarks = remarks + "欠费收取";

        if (totalMoney.compareTo(dbTotalMoney) != 0) {
            throw new SystemException("总计金额不一致", String.format("dbTotalMoney[%s]", dbTotalMoney));
        }

        //转存预存,默认为零
        BigDecimal advanceReturn = BigDecimal.ZERO;
        //使用预存，默认为零
        BigDecimal advanceUse = BigDecimal.ZERO;
        //收款剩余金额
        BigDecimal remainMoney = chargeMoney.subtract(totalMoney);
        //获取预存余额
        BigDecimal balance = walletService.findBalance(buildingId, WalletType.PARKING);

        //如果收款剩余金额大于等于0,且转存，则转存金额为收款剩余金额
        if (remainMoney.compareTo(BigDecimal.ZERO) >= 0 && storageReturn) {
            advanceReturn = remainMoney;
        } else if (remainMoney.compareTo(BigDecimal.ZERO) < 0) {
            //收款剩余金额小于零，且使用预存
            if (useStorage) {
                //预存余额不足
                if (balance.add(remainMoney).compareTo(BigDecimal.ZERO) < 0) {
                    throw new BusinessException("缴费金额不足", String.format("使用预存，预存余额[%s], 剩余缴费[%s]", balance, remainMoney.abs()));
                } else {
                    //使用的预存为，剩余的未缴费用
                    advanceUse = remainMoney.abs();
                }
            } else {
                throw new BusinessException("缴费金额不足", String.format("不使用预存，剩余缴费[%s]", remainMoney.abs()));
            }
        }

        User user = userService.getUser(userId);

        String billNo = snowflakeIdWorker.nextId() + "";


        Integer payId = parkingRentPayRecordService.pay(user, buildingId, arrearsList.get(0).getRentId(), totalMoney, chargeMoney, advanceUse, advanceReturn, payType, remarks, billNo, ParkingRentPayRecordEntity.TYPE_ARREARS, dbTotalMoney, FlowingWaterEntity.OTHER_TYPE_ARREARS);

        charge(arrearsIdList, payId);

        if (print) {
            ArrearsPayBillVo bill = new ArrearsPayBillVo();

            Building building = buildingService.findBuilding(buildingId);
            Village village = villageService.findVillage(building.getVillageId());
            ParkingRentEntity parkingRentEntity = parkingRentService.getById(arrearsList.get(0).getRentId());

            bill.setTitle(patee + "收款收据");
            bill.setBillNo(billNo);
            bill.setVillageName(village.getName());
            bill.setAddress(buildingService.findAddress(building));
            bill.setOwnerName(parkingRentEntity.getUserName());
            bill.setPayTime(LocalDate.now());
            bill.setPayee(user.getUserName());
            bill.setReceiveUnit(receiveUnit);

            List<ArrearsPayBillVo.BillDetail> billDetails = arrearsList.stream().map(arrears -> {
                ArrearsPayBillVo.BillDetail billDetail = new ArrearsPayBillVo.BillDetail();

                billDetail.setFeeType("车位租金");
                billDetail.setYearMonth(arrears.getYearMonth());
                billDetail.setMoney(arrears.getMoney());
                billDetail.setRemark("欠费缴纳");

                return billDetail;
            }).collect(Collectors.toList());

            bill.setBillDetails(billDetails);

            bill.setTotalAmount(totalMoney);
            bill.setReceiveAmount(chargeMoney);
            bill.setDeductionAmount(BigDecimal.ZERO);
            bill.setPreAmount(balance);
            bill.setThisAmount(advanceUse);
            BigDecimal currentbalance = walletService.findBalance(buildingId, WalletType.PARKING);
            bill.setReturnAmount(currentbalance);
            bill.setRealAmount(totalMoney);
            bill.setChineseAmount(NumberToCn.number2Cn(totalMoney));


            return bill;
        } else {
            return null;
        }
    }

    private List<ParkingRentArrearsEntity> getList(Collection<Integer> arrearsIds) {

        QueryWrapper<ParkingRentArrearsEntity> wrapper = new QueryWrapper<>();
        wrapper.in("id", arrearsIds);

        return parkingRentArrearsMapper.selectList(wrapper);
    }

    public void undoCharge(Integer payId) {
        UpdateWrapper<ParkingRentArrearsEntity> wrapper = new UpdateWrapper<>();
        wrapper.set("state", ParkingRentArrearsEntity.STATE_NOT_PAY);
        wrapper.eq("pay_id", payId);

        parkingRentArrearsMapper.update(null, wrapper);
    }

    private void charge(Collection<Integer> arrearsIds, Integer payId) {
        UpdateWrapper<ParkingRentArrearsEntity> wrapper = new UpdateWrapper<>();
        wrapper.set("state", ParkingRentArrearsEntity.STATE_PAID);
        wrapper.set("pay_id", payId);
        wrapper.in("id", arrearsIds);

        //更新缴费时间
        String chargeTime = DateFormatUtils.format(new Date(), "yyyy-MM");
        wrapper.set("charge_time", chargeTime);

        parkingRentArrearsMapper.update(null, wrapper);
    }


    private void setCell(ParkingRentArrearsDetailVo parkingRentArrearsDetailVo, XSSFRow rw) {
        rw.createCell(0).setCellValue(parkingRentArrearsDetailVo.getVillageName());
        rw.createCell(1).setCellValue(parkingRentArrearsDetailVo.getBuilding() + "栋-" + parkingRentArrearsDetailVo.getUnit() + "单元-" + parkingRentArrearsDetailVo.getRoomNumber());
        rw.createCell(2).setCellValue(parkingRentArrearsDetailVo.getMoney().doubleValue());
        rw.createCell(3).setCellValue(parkingRentArrearsDetailVo.getYearMonth());
        rw.createCell(4).setCellValue(parkingRentArrearsDetailVo.getUserName());
        rw.createCell(5).setCellValue(parkingRentArrearsDetailVo.getPhone());
        rw.createCell(6).setCellValue(parkingRentArrearsDetailVo.getRemark());
    }

    @Autowired
    public void setParkingRentArrearsMapper(ParkingRentArrearsMapper parkingRentArrearsMapper) {
        this.parkingRentArrearsMapper = parkingRentArrearsMapper;
    }

    @Autowired
    public void setWalletService(WalletService walletService) {
        this.walletService = walletService;
    }

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Autowired
    public void setParkingRentPayRecordService(ParkingRentPayRecordService parkingRentPayRecordService) {
        this.parkingRentPayRecordService = parkingRentPayRecordService;
    }

    @Autowired
    public void setSnowflakeIdWorker(SnowflakeIdWorker snowflakeIdWorker) {
        this.snowflakeIdWorker = snowflakeIdWorker;
    }

    @Autowired
    public void setVillageService(VillageService villageService) {
        this.villageService = villageService;
    }

    @Autowired
    public void setBuildingService(BuildingService buildingService) {
        this.buildingService = buildingService;
    }

    @Autowired
    public void setParkingRentService(ParkingRentService parkingRentService) {
        this.parkingRentService = parkingRentService;
    }
}
